<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html><head>
  
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8">

  
  <link href="../css/style.css" rel="stylesheet" type="text/css">

</head>
<body>
<h1>4.8. Циклы и команда LOOP</h1>
<p class="article">
Синтаксис объявления меток
Метка представляет собой символическое имя, вместо которого компилятор подставляет адрес. В программе на ассемблере можно присвоить имя любому адресу в коде или данных. Обычно метки используются для организации переходов, циклов или каких-то манипуляций с данными. По сути имена переменных, объявленных с помощью директив объявления данных, тоже являются метками. Но с ними компилятор дополнительно связывает размер переменной. Метка объявляется очень просто: достаточно в начале строки написать имя и поставить двоеточие. Например:
</p>
<pre class="code">
m1: mov ax,4C00h
    int 21h
</pre>
<p class="article">
Теперь вместо имени m1 компилятор везде будет подставлять адрес комады mov ax,4C00h. Можно объявлять метку на пустой строке перед командой:
</p>
<pre class="code">
exit_app:
    mov ax,4C00h
    int 21h
</pre>
<p class="article">
Имя метки может состоять из латинских букв, цифр и символов подчёркивания, но должно начинаться с буквы. Имя метки должно быть уникальным. В качестве имени метки нельзя использовать директивы и ключевые слова компилятора, названия команд и регистров (в этом случае FASM покажет сообщение об ошибке). FASM различает регистр символов в именах меток. Можно также объявлять несколько меток на один адрес. Например:
</p>
<pre class="code">
no_error:
exit_app:
m1: mov ax,4C00h
</pre>
<h2>Команда LOOP</h2>
<p class="article">
Для организации цикла предназначена команда LOOP. У этой команды один операнд — имя метки, на которую осуществляется переход. В качестве счётчика цикла используется регистр CX. Команда LOOP выполняет декремент CX, а затем проверяет его значение. Если содержимое CX не равно нулю, то осуществляется переход на метку, иначе управление переходит к следующей после LOOP команде.
Содержимое CX интерпретируется командой как число без знака. В CX нужно помещать число, равное требуемому количеству повторений цикла. Понятно, что максимально может быть 65535 повторений. Ещё одно ограничение связано с дальность перехода. Метка должна находиться в диапазоне -127…+128 байт от команды LOOP (если это не так, FASM сообщит об ошибке). Пример:
</p>
<pre class="code">
use16                 ;Генерировать 16-битный код
org 100h              ;Программа начинается с адреса 100h
 
    mov ah,02h        ;Для вызова функции DOS 02h - вывод символа
    mov dl,'A'        ;Первый выводимый символ
    mov cx,26         ;Счётчик повторений цикла
metka:
    int 21h           ;Обращение к функции DOS
    inc dl            ;Следующий символ
    loop metka        ;Команда цикла
 
    mov ah,09h        ;Функция DOS 09h - вывод строки
    mov dx,press      ;В DX адрес строки
    int 21h           ;Обращение к функции DOS
 
    mov ah,08h        ;Функция DOS 08h - ввод символа без эха
    int 21h           ;Обращение к функции DOS
 
    mov ax,4C00h      ;\
    int 21h           ;/ Завершение программы
;-------------------------------------------------------
press:
    db 13,10,'Press any key...$'
</pre>
<div class="noteclassic">
Использование loop аналогично конструкции for в языках высокого уровня. Количество 
повторений цикла заносится в регистр CX.
</div>
<p class="article">
Команды «int 21h» и «inc dl» (строки 8 и 9) будут выполняться в цикле 26 раз. Для того, чтобы программа не закрылась сразу, используется функция DOS 08h — ввод символа с клавиатуры без эха, то есть вводимый символ не отображается. Перед этим выводится предложение нажать любую кнопку (но Reset лучше не нажимать). Для примера адрес строки объявлен с помощью метки. Символы с кодами 13 и 10 обозначают переход на следующую строку (символ 13(0Dh) называется CR — Carriage Return — возврат каретки, а символ 10(0Ah) LF — Line Feed — перевод строки . Эти символы унаследованы со времён древних телетайпов, когда текст печатался, как на печатной машинке). 
</p>
<h2>Вложенные циклы</h2>
<p class="article">
Иногда требуется организовать вложенный цикл, то есть цикл внутри другого цикла. В этом случае необходимо сохранить значение CX перед началом вложенного цикла и восстановить после его завершения (перед командой LOOP внешнего цикла). Сохранить значение можно в другой регистр, во временную переменную или в стек. Следующая программа выводит все доступные ASCII-символы в виде таблицы 16×16. Значение счётчика внешнего цикла сохраняется в регистре BX.
</p>
<pre class="code">
use16                 ;Генерировать 16-битный код
org 100h              ;Программа начинается с адреса 100h
 
    mov ah,02h        ;Для вызова функции DOS 02h - вывод символа
    sub dl,dl         ;Первый выводимый символ
    mov cx,16         ;Счётчик внешнего цикла (по строкам)
lp1:
    mov bx,cx         ;Сохраняем счётчик в BX
    mov cx,16         ;Счётчик внутреннего цикла (по столбцам)
lp2:
    int 21h           ;Обращение к функции DOS
    inc dl            ;Следующий символ
    loop lp2          ;Команда внутреннего цикла
 
    mov dh,dl         ;Сохраняем значение DL в DH
    mov dl,13         ;\
    int 21h           ; \
    mov dl,10         ; / Переход на следующую строку
    int 21h           ;/
    mov dl,dh         ;Восстанавливаем значение DL
 
    mov cx,bx         ;Восстанавливаем значение счётчика
    loop lp1          ;Команда внешнего цикла
 
    mov ah,09h        ;Функция DOS 09h - вывод строки
    mov dx,press      ;В DX адрес строки
    int 21h           ;Обращение к функции DOS
 
    mov ah,08h        ;Функция DOS 08h - ввод символа без эха
    int 21h           ;Обращение к функции DOS
 
    mov ax,4C00h      ;\
    int 21h           ;/ Завершение программы
;-------------------------------------------------------
press db 13,10,'Press any key...$'
</pre>

</body>
</html>
